#include "No7pch.h"
#include "Application.h"
#include "No7/Core/Log.h"
#include "No7/Core/Input.h"
#include "No7/Core/Renderer/Renderer.h"
#include "No7/Core/CoreMacros.h"

#define BIND_EVENT_FUNCTION(x) std::bind(&x, this, std::placeholders::_1)

nmspc::Application* nmspc::Application::application = nullptr;

nmspc::Application::Application()
{
	NO7_CORE_ASSERT(!nmspc::Application::application, "Application already exists!");
	nmspc::Application::application = this;
	this->cur_window = std::unique_ptr<nmspc::Window>(nmspc::Window::create());
	this->cur_window->setEventCallback(BIND_EVENT_FUNCTION(nmspc::Application::onEvent));
	this->imgui_layer = new nmspc::ImGuiLayer();
	this->pushOverlay(this->imgui_layer);
}

nmspc::Application::~Application()
{
}

bool nmspc::Application::onWindowClosed(nmspc::WindowCloseEvent& e)
{
	this->if_running = false;
	return true;
}

void nmspc::Application::run()
{
	while (this->if_running)
	{
		for (nmspc::Layer* layer : this->layer_stack)
		{
			layer->onUpdate();
		}
		this->imgui_layer->begin();
		for (nmspc::Layer* layer : this->layer_stack)
		{
			layer->onImGuiRender();
		}
		this->imgui_layer->end();
		this->cur_window->onUpdate();
	}
}

void nmspc::Application::onEvent(nmspc::Event& e)
{
	nmspc::EventDispatcher event_dispatcher(e);
	event_dispatcher.dispatch<nmspc::WindowCloseEvent>(BIND_EVENT_FUNCTION(nmspc::Application::onWindowClosed));
	for (auto iter = this->layer_stack.end(); iter != this->layer_stack.begin();)
	{
		(*--iter)->onEvent(e);
		if (e.if_handled)
		{
			break;
		}
	}
}

void nmspc::Application::pushLayer(nmspc::Layer* layer)
{
	this->layer_stack.pushLayer(layer);
	layer->onAttach();
}

void nmspc::Application::pushOverlay(nmspc::Layer* layer)
{
	this->layer_stack.pushOverlay(layer);
	layer->onAttach();
}
